#include "AnsysEDCOM.h"

AnsysEDCOM::AnsysEDCOM(const wchar_t* ProgID) {
    hr = CoInitialize(NULL);
    if (FAILED(hr)) {
        std::cerr << "Failed to initialize COM library." << std::endl;
    }
    hr = CLSIDFromProgID(ProgID, &clsid);
    if (FAILED(hr)) {
        std::cerr << "Failed to get CLSID for Ansys Maxwell." << std::endl;
        CoUninitialize();
    }
    hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);
    if (FAILED(hr)) {
        std::cerr << "Failed to create Ansoft Electronics Desktop instance." << std::endl;
        CoUninitialize();
    }
    hr = pUnknown->QueryInterface(IID_IDispatch, (void**)&AppDesktop);
    if (FAILED(hr)) {
        std::cerr << "Failed to get IAppDesktop interface." << std::endl;
        pUnknown->Release();
        CoUninitialize();
    }
    VariantInit(&result);
}
AnsysEDCOM::~AnsysEDCOM() {
    AppDesktop->Release();
    pUnknown->Release();
    CoUninitialize();
}
IDispatch* AnsysEDCOM::InvokeMethod(IDispatch* pDispatch, OLECHAR* methodName, std::vector<std::any> params_vector) {
    hr = pDispatch->GetIDsOfNames(IID_NULL, &methodName, 1, LOCALE_USER_DEFAULT, &dispid);
    if (FAILED(hr)) {
        std::wcout << "Failed to get ID of " << methodName << " method." << std::endl;
        pDispatch->Release();
        pUnknown->Release();
        CoUninitialize();
        return nullptr;
    }
    unsigned int sizeofParams = params_vector.size();
    size_t indexofParams{ 1 };
    if (sizeofParams != 0) {
        if (params_vector[0].type() == typeid(char const*) && strcmp(std::any_cast<char const*>(params_vector[0]), "") == 0) {
            sizeofParams = params_vector.size() - 1;
            indexofParams = 0;
        }
    }
    CComVariant* vtArgs = new CComVariant[sizeofParams];
    DISPPARAMS params;
    if (sizeofParams == 0) {
        params = { nullptr, nullptr, sizeofParams, 0 };
    }
    else {
        for (const auto& item : params_vector) {
            if (item.type() == typeid(std::vector<std::any>)) {
                vtArgs[sizeofParams - indexofParams].vt = VT_ARRAY | VT_VARIANT;
                vtArgs[sizeofParams - indexofParams].parray = parsingParams(std::any_cast<std::vector<std::any>>(item));
            }
            else if (item.type() == typeid(bool)) {
                vtArgs[sizeofParams - indexofParams] = CComVariant(std::any_cast<bool>(item));
            }
            else if (item.type() == typeid(const wchar_t*)) {
                vtArgs[sizeofParams - indexofParams] = CComVariant(std::any_cast<const wchar_t*>(item));
            }
            else if (item.type() == typeid(int)) {
                vtArgs[sizeofParams - indexofParams] = CComVariant(std::any_cast<int>(item));
            }
            else if (item.type() == typeid(double)) {
                vtArgs[sizeofParams - indexofParams] = CComVariant(std::any_cast<double>(item));
            }
            indexofParams++;
        }
        params = { vtArgs, nullptr, sizeofParams, 0 };
    }
    hr = pDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &result, NULL, NULL);
    if (FAILED(hr)) {
        std::wcout << "Failed to invoke " << methodName << " method." << std::endl;
        pDispatch->Release();
        pUnknown->Release();
        CoUninitialize();
        return nullptr;
    }
    return  result.pdispVal;
}
IDispatch* AnsysEDCOM::getAppDesktop() {
    return AppDesktop;
}
SAFEARRAY* AnsysEDCOM::parsingParams(std::vector<std::any > Params_) {
    std::vector<std::any> params = std::any_cast<std::vector<std::any>>(Params_);
    SAFEARRAYBOUND innerBounds = { params.size(), 0 };
    SAFEARRAY* innerArray = SafeArrayCreate(VT_VARIANT, 1, &innerBounds);
    long index{ 0 };
    for (const auto& item : params) {
        if (item.type() == typeid(std::vector<std::any>)) {
            CComVariant innerVar;
            innerVar.vt = VT_ARRAY | VT_VARIANT;
            innerVar.parray = parsingParams(std::any_cast<std::vector<std::any>>(item));
            SafeArrayPutElement(innerArray, &index, &innerVar);
        }
        if (item.type() == typeid(bool)) {
            SafeArrayPutElement(innerArray, &index, &CComVariant(std::any_cast<bool>(item)));
            //vtArgs[sizeofParams - indexofParams] = CComVariant(std::any_cast<bool>(item));
        }
        else if (item.type() == typeid(const wchar_t*)) {
            SafeArrayPutElement(innerArray, &index, &CComVariant(std::any_cast<const wchar_t*>(item)));
        }
        else if (item.type() == typeid(int)) {
            SafeArrayPutElement(innerArray, &index, &CComVariant(std::any_cast<int>(item)));
        }
        else if (item.type() == typeid(double)) {
            SafeArrayPutElement(innerArray, &index, &CComVariant(std::any_cast<double>(item)));
        }
        index++;
    }
    return innerArray;
}